home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i052: Network News Transfer Protocol, version 1.5, Part06/09
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Phil Lapsley <phil@ucbvax.berkeley.edu>
- Posting-number: Volume 14, Issue 52
- Archive-name: nntp1.5/part06
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 6 (of 9)."
- # Contents: ./CHANGES ./common/clientlib.c ./server/newnews.c
- # ./xfer/nntpxfer.c ./xmit/remote.c
- # Wrapped by rsalz@fig.bbn.com on Tue Apr 19 18:16:45 1988
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f './CHANGES' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./CHANGES'\"
- else
- echo shar: Extracting \"'./CHANGES'\" \(9242 characters\)
- sed "s/^X//" >'./CHANGES' <<'END_OF_FILE'
- X
- X This file describes the changes which have been made in NNTP
- since the initial release. Individuals who either reported or
- inspired the bug/bug fix are in square brackets.
- X
- X1.5 February 26, 1988
- X
- X New top level Makefile. [Casey Leedom, casey@lll-crg.llnl.gov]
- X
- X Now using strcasecmp/strncasecmp instead of streql/strneql.
- X Due credit is given to the University of California at [sic]
- X Berkeley for the use of this software. :-)
- X
- X Combined common/response_codes.h and common/rfc977.h into
- X common/nntp.h.
- X
- X Better fix for getifnetmask ioctl returning 0 netmask.
- X
- X Patch to Configure to handle domains for non-portable code.
- X [Brad Smith, brad@saturn.ucsc.edu]
- X
- X New version of nntpxmit with article retransmission.
- X [Erik Fair, fair@ucbarpa.Berkeley.EDU].
- X
- X System V compatability; will now compile on Hockey-Pux (HPUX).
- X [Stan Barber, sob%soma.tmc.edu@tmc.edu]
- X
- X EXCELAN TCP support. [Stan Barber, sob%soma.tmc.edu@tmc.edu]
- X
- X server/subnet.c now supports compiled-in netmasks.
- X This is useful if you want subnet support on machines
- X that don't have the necessary ioctls for determining
- X network masks on a per-interface basis.
- X
- X Fake syslog support included for real this time.
- X
- X1.4 October 15, 1987
- X
- X Reorganized documentation directory. Thanks for the
- X extraction stuff, Stan. [Stan Barber, sob%%soma.uucp@rice.edu]
- X
- X Added transfer timeouts. [Steve Schoch, schoch@ames.arpa]
- X
- X Fixed a problem with IHAVE which allowed a remote machine to
- X repeatedly feed you articles that you expired (although all
- X you'd do with them is throw them away).
- X [Fred Avolio, avolio@decuac.dec.com]
- X
- X DECNet support (see server/dnet_access.c and common/clientlib.c).
- X [Matt Thomas, thomas%syrah.dec@decwrl.dec.com]
- X
- X Fixed serious joe code in distribution checks in NEWNEWS.
- X
- X NEWNEWS statistics.
- X
- X Newsgroup security.
- X
- X Performance enhancements (about 2x better for article xfers).
- X
- X xhdr command added to improve performance on subject searches.
- X
- X Compiled-in server name no longer supported.
- X
- X common/clientlib.c/getserverbyfile() now looks at the
- X environment variable NNTPSERVER before checking the file.
- X
- X inews/inews.c now limits .signature files to MAX_SIGNATURE lines.
- X
- X server/misc.c/spawn() now returns the error output of rnews/inews
- X alone with the posting failed code. This is in turn printed by
- X inews/inews.c so the user has some idea of why his article wasn't
- X accepted.
- X
- X rn patches now for patchlevel #40
- X Bug fix: rrn no longer leaves droppings in /tmp
- X "Skipping unavailable article" problems fixed
- X Support for 4.3 TIOCGWINSZ ioctl [sam@okeeffe.berkeley.edu]
- X Configure asks for domains
- X Pnews/Rnmail understand hostnames with .'s in them.
- X Makefile fixes [harvard!lownlab!kiely]
- X
- X PYRAMID #defines removed, as it is all being done by default now.
- X
- X inews/inews.c now exits 0, since before it had a random exit
- X status, causing pyramids to choke. [forys@boulder.colorado.edu]
- X
- X server/server.c now logs user/system/elapsed time as floats
- X instead of ints. [rick@seismo.css.gov]
- X
- X server/ihave.c no longer logs every message id transfered but
- X instead keeps statistics which are logged at the end.
- X [rick@seismo.css.gov]
- X
- X server/serve.c now times out after TIMEOUT seconds of idleness.
- X
- X server/access.c converts remote hostname to lower case
- X when logging, in case you have a nameserver which is helping you.
- X
- X server/misc.c/getartbyid now reports message-id's when
- X it encounters a malformed line in the history file.
- X [gds@spam.istc.sri.com]
- X
- X inews/inews.c had an uninitialized variable, which
- X could cause trouble. [jwp%chem@sdcsvax.ucsd.edu]
- X
- X common/clientlib.c now understands 4.3 nameserver
- X multiple addresses, and tries them all before
- X giving up.
- X
- X common/clientlib.c has has 2 new functions:
- X "getserverbyfile" opens a given file and returns
- X the name of the server given in the file to use
- X for news. "handle_server_response" prints informative
- X messages based on the initial connection response code.
- X
- X server/access.c now is case insensitive when checking
- X for host read/xfer permissions.
- X
- X server/misc.c/spawn didn't check for a closed connection
- X while receiving input from client. As a result, truncated
- X news articles could be received.
- X
- X server/newnews.c had a printf which was missing an
- X argument. [louie@trantor.umd.edu]
- X
- X Added fake syslog facility to server. Code is in
- X server/fakesyslog.c. [mckenny@sri-unix.arpa]
- X
- X Fixed length argument to accept() in server/main.c
- X [mckenny@sri-unix.arpa]
- X
- X Now uses pipe to rnews so as to get rnews output for debugging.
- X Also chowns temporary file to POSTER's uid and gid.
- X [mckenny@sri-unix.arpa]
- X
- X Fixed bugs in server/netaux.c to close syslog fd.
- X [mckenny@sri-unix.arpa]
- X
- X Made bcopy() standard in server/misc.c [kre@munnari.OZ]
- X
- X Documentation changes to make certain things about client
- X installation clearer. [munnari!charlie.oz!craig]
- X
- X1.3 30 June 1986
- X
- X rrn is no longer included as complete source, but
- X rather as a set of context diffs and a program to
- X apply them to your rn source. Many thanks go to
- X Gene Spafford for an outstanding job doing this.
- X [spaf@gatech.csnet]
- X
- X The dreaded kill/save bug is fixed; rn was passing
- X /bin/sh too many open file descriptors. Thanks and a tip of the
- X proverbial hat to Chris Maio! Change to rrn/util.c.
- X [chris@columbia.edu]
- X
- X Fixed a bug in rrn/artio.c which caused an assertion
- X failure on line 114 of artio.c; artopen was returning
- X Nullfp without closing the fp associated with the
- X bogus article. [genrad!ens@eddie.mit.edu, beorn@ic.berkeley.edu]
- X
- X Added #define PYRAMID in common/conf.h, added some
- X #ifdef PYRAMID code in server/misc.c to deal with
- X Pyramids not initializing static data to 0, as well
- X as an fseek problem. [spaf@gatech.CSNET]
- X
- X Another wait bug fixed in spawn() in server/misc.c.
- X
- X Added a required \r in post.c.
- X
- X Added signal(SIGCHLD, SIG_IGN) to server/serve.c,
- X to fix exit status problem with ALONE defined.
- X
- X Statistics logging now returns sum of the nntpd and
- X its children for process time. server/main.c
- X [fair@ucbarpa.berkeley.edu]
- X
- X Subnet support for access file finally added.
- X server/subnet.c added, common/conf.h now has
- X #defines for SUBNET, DAMAGED_NETMASK.
- X
- X inews/inews.c now generates a from line with the UUCP
- X name instead of always using gethostname(). common/conf.h
- X changed to add #defines for UUNAME, GHNAME.
- X [jwang@atrp.mit.edu]
- X
- X Added LIBS to Makefile. [soma!sob@rice.edu]
- X
- X1.2c 17 May 1986
- X
- X Support for Masscomp added (#define MASSCOMP in ../common/conf.h).
- X [soma!sob@rice.edu]
- X
- X Syslog output now requires SYSLOG to be defined in ../common/conf.h.
- X This is handy on systems which, for some reason or another,
- X don't have syslog. [soma!sob@rice.edu]
- X
- X server/post.c had arguments reversed in a printf. [salex@rice.edu]
- X
- X rrn/common.h had PIPESAVER misdefined. [cspencer@bbncc5.arpa]
- X
- X server/group.c was missing a \r in a printf. [lear@rutgers.edu]
- X
- X xmit/nntpxmit.c is a new version. Highlights include
- X improved error reactions and logging info. [fair@ucbarpa.berkeley.edu]
- X
- X xmit/nntpsend is a shell script for sending news via nntp
- X in a sane manner, with locking. [pleasant@topaz.rutgers.edu,
- X fair@ucbarpa.berkeley.edu] The locking mechanism is provided
- X courtesy of Mr. Fair's "shlock.c", in xmit/shlock.c.
- X
- X support/nntp_awk produces weekly reports from the nntp server
- X logging output. [fair@ucbarpa.berkeley.edu]
- X
- X Makefile (in this directory) would do a "make install" as
- X the default action; it now prints a helpful message.
- X [arnold@cgl.ucsf.edu]
- X
- X server/Makefile and support/Makefile had needless dependencies
- X in them; if you didn't do a make depend, you'd have problems
- X on a 4.2 system. The server and support stuff now depend only
- X on their own .h files. [arnold@cgl.ucsf.edu]
- X
- X1.2b 13 April 1986
- X
- X common/clientlib.c stupidly had some debugging printfs
- X enabled.
- X
- X rrn/{artio.c,head.c} had sprintf("... %d", foo) where "foo"
- X was a long. %d -> %ld. [cspencer@bbncc5.arpa]
- X
- X server/time.c had an order of evaluation problem in the
- X macro "twodigtoi". [fletcher@tzec.cs.utexas.edu, among others.]
- X
- X server/common.h included <dbm.h> if DBM was defined,
- X caused multiply-defined NULL's. [cda@opal.berkeley.edu,
- X pleasant@topaz.rutgers.edu, among others.]
- X
- X server/active.c would lose because variable "i" would be
- X at the end of the group array if it was called on a timer
- X interrupt. "i" now set to zero properly. This only occurs
- X if FASTFORK is defined. [cda@opal.berkeley.edu]
- X
- X1.2a 20 March 1986
- X
- X common/conf.h defined MAX_GROUPS as 300; this was too low on
- X some machines. Upped to 450. [solex@rice.edu, beorn@ic.berkeley.edu]
- X
- X rrn/Makefile.sh had .c instead of .o for OBJS and SRCS
- X respectively. Also had cc -o ../common/clientlib.o (see below).
- X
- X inews/inews.c had (char *) 0 for gets(), which made SUN's upset.
- X Changed to simply NULL. [brian@sdcsvax.ucsd.edu]
- X
- X inews/Makefile had cc -o ../common/clientlib.o which some
- X machines don't do. [brian@sdcsvax.ucsd.edu]
- X
- X common/clientlib.c has "untp" instead of "nntp".
- X
- X server/active.c made more robust about reading active file
- X if active file is longer than MAX_GROUPS.
- X
- X server/common.h included common/conf.h after checking for
- X DBM, which caused some problems. [soma!sob@rice.edu]
- X
- X1.2 15 March 1986
- X
- X Released.
- END_OF_FILE
- if test 9242 -ne `wc -c <'./CHANGES'`; then
- echo shar: \"'./CHANGES'\" unpacked with wrong size!
- fi
- # end of './CHANGES'
- fi
- if test -f './common/clientlib.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./common/clientlib.c'\"
- else
- echo shar: Extracting \"'./common/clientlib.c'\" \(10189 characters\)
- sed "s/^X//" >'./common/clientlib.c' <<'END_OF_FILE'
- X#ifndef lint
- static char *sccsid = "@(#)clientlib.c 1.9 (Berkeley) 2/25/88";
- X#endif
- X
- X/*
- X * NNTP client routines.
- X */
- X
- X/*
- X * Include configuration parameters only if we're made in the nntp tree.
- X */
- X
- X#ifdef NNTPSRC
- X#include "../common/conf.h"
- X#endif NNTPSRC
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#ifndef EXCELAN
- X# include <netdb.h>
- X#endif not EXCELAN
- X
- X#ifdef USG
- X# define index strchr
- X#endif USG
- X
- X#ifdef EXCELAN
- X# define IPPORT_NNTP 119
- X#endif
- X
- X#ifdef DECNET
- X#include <netdnet/dn.h>
- X#include <netdnet/dnetdb.h>
- X#endif DECNET
- X
- X#include "nntp.h"
- X
- FILE *ser_rd_fp = NULL;
- FILE *ser_wr_fp = NULL;
- X
- X/*
- X * getserverbyfile Get the name of a server from a named file.
- X * Handle white space and comments.
- X * Use NNTPSERVER environment variable if set.
- X *
- X * Parameters: "file" is the name of the file to read.
- X *
- X * Returns: Pointer to static data area containing the
- X * first non-ws/comment line in the file.
- X * NULL on error (or lack of entry in file).
- X *
- X * Side effects: None.
- X */
- X
- char *
- getserverbyfile(file)
- char *file;
- X{
- X register FILE *fp;
- X register char *cp;
- X static char buf[256];
- X char *index();
- X char *getenv();
- X char *strcpy();
- X
- X if (cp = getenv("NNTPSERVER")) {
- X (void) strcpy(buf, cp);
- X return (buf);
- X }
- X
- X if (file == NULL)
- X return (NULL);
- X
- X fp = fopen(file, "r");
- X if (fp == NULL)
- X return (NULL);
- X
- X while (fgets(buf, sizeof (buf), fp) != NULL) {
- X if (*buf == '\n' || *buf == '#')
- X continue;
- X cp = index(buf, '\n');
- X if (cp)
- X *cp = '\0';
- X (void) fclose(fp);
- X return (buf);
- X }
- X
- X (void) fclose(fp);
- X return (NULL); /* No entry */
- X}
- X
- X
- X/*
- X * server_init Get a connection to the remote news server.
- X *
- X * Parameters: "machine" is the machine to connect to.
- X *
- X * Returns: -1 on error
- X * server's initial response code on success.
- X *
- X * Side effects: Connects to server.
- X * "ser_rd_fp" and "ser_wr_fp" are fp's
- X * for reading and writing to server.
- X */
- X
- server_init(machine)
- char *machine;
- X{
- X int sockt_rd, sockt_wr;
- X char line[256];
- X char *index();
- X#ifdef DECNET
- X char *cp;
- X
- X cp = index(machine, ':');
- X
- X if (cp && cp[1] == ':') {
- X *cp = '\0';
- X sockt_rd = get_dnet_socket(machine);
- X } else
- X sockt_rd = get_tcp_socket(machine);
- X#else
- X sockt_rd = get_tcp_socket(machine);
- X#endif
- X
- X if (sockt_rd < 0)
- X return (-1);
- X
- X /*
- X * Now we'll make file pointers (i.e., buffered I/O) out of
- X * the socket file descriptor. Note that we can't just
- X * open a fp for reading and writing -- we have to open
- X * up two separate fp's, one for reading, one for writing.
- X */
- X
- X if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
- X perror("server_init: fdopen #1");
- X return (-1);
- X }
- X
- X sockt_wr = dup(sockt_rd);
- X if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
- X perror("server_init: fdopen #2");
- X ser_rd_fp = NULL; /* from above */
- X return (-1);
- X }
- X
- X /* Now get the server's signon message */
- X
- X (void) get_server(line, sizeof(line));
- X return (atoi(line));
- X}
- X
- X
- X/*
- X * get_tcp_socket -- get us a socket connected to the news server.
- X *
- X * Parameters: "machine" is the machine the server is running on.
- X *
- X * Returns: Socket connected to the news server if
- X * all is ok, else -1 on error.
- X *
- X * Side effects: Connects to server.
- X *
- X * Errors: Printed via perror.
- X */
- X
- get_tcp_socket(machine)
- char *machine;
- X{
- X int s;
- X struct sockaddr_in sin;
- X#ifndef EXCELAN
- X struct servent *getservbyname(), *sp;
- X struct hostent *gethostbyname(), *hp;
- X#ifdef h_addr
- X int x = 0;
- X register char **cp;
- X#endif h_addr
- X
- X if ((sp = getservbyname("nntp", "tcp")) == NULL) {
- X fprintf(stderr, "nntp/tcp: Unknown service.\n");
- X return (-1);
- X }
- X
- X if ((hp = gethostbyname(machine)) == NULL) {
- X fprintf(stderr, "%s: Unknown host.\n", machine);
- X return (-1);
- X }
- X
- X bzero((char *) &sin, sizeof(sin));
- X sin.sin_family = hp->h_addrtype;
- X sin.sin_port = sp->s_port;
- X#else EXCELAN
- X bzero((char *) &sin, sizeof(sin));
- X sin.sin_family = AF_INET;
- X sin.sin_port = htons(IPPORT_NNTP);
- X#endif EXCELAN
- X
- X /*
- X * The following is kinda gross. The name server under 4.3
- X * returns a list of addresses, each of which should be tried
- X * in turn if the previous one fails. However, 4.2 hostent
- X * structure doesn't have this list of addresses.
- X * Under 4.3, h_addr is a #define to h_addr_list[0].
- X * We use this to figure out whether to include the NS specific
- X * code...
- X */
- X
- X#ifdef h_addr
- X
- X /* get a socket and initiate connection -- use multiple addresses */
- X
- X for (cp = hp->h_addr_list; cp && *cp; cp++) {
- X s = socket(hp->h_addrtype, SOCK_STREAM, 0);
- X if (s < 0) {
- X perror("socket");
- X return (-1);
- X }
- X bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
- X
- X if (x < 0)
- X fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
- X x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
- X if (x == 0)
- X break;
- X fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
- X perror("");
- X (void) close(s);
- X }
- X if (x < 0) {
- X fprintf(stderr, "giving up...\n");
- X return (-1);
- X }
- X#else /* no name server */
- X#ifdef EXCELAN
- X if ((s = rresvport(SO_KEEPALIVE)) < 0)
- X {
- X /* Get the socket */
- X perror("socket");
- X return (-1);
- X }
- X /* set up addr for the connect */
- X sin.sin_addr.s_addr = rhost(machine);
- X if (sin.sin_addr.s_addr < 0){
- X fprintf(stderr, "%s: Unknown host.\n", machine);
- X return (-1);
- X }
- X /* And then connect */
- X
- X if (connect(s, &sin) < 0) {
- X perror("connect");
- X (void) close(s);
- X return (-1);
- X }
- X#else not EXCELAN
- X if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- X perror("socket");
- X return (-1);
- X }
- X
- X /* And then connect */
- X
- X bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
- X if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- X perror("connect");
- X (void) close(s);
- X return (-1);
- X }
- X
- X#endif not EXCELAN
- X#endif
- X
- X return (s);
- X}
- X
- X#ifdef DECNET
- X/*
- X * get_dnet_socket -- get us a socket connected to the news server.
- X *
- X * Parameters: "machine" is the machine the server is running on.
- X *
- X * Returns: Socket connected to the news server if
- X * all is ok, else -1 on error.
- X *
- X * Side effects: Connects to server.
- X *
- X * Errors: Printed via nerror.
- X */
- X
- get_dnet_socket(machine)
- char *machine;
- X{
- X int s, area, node;
- X struct sockaddr_dn sdn;
- X struct nodeent *getnodebyname(), *np;
- X
- X bzero((char *) &sdn, sizeof(sdn));
- X
- X switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
- X case 1:
- X node = area;
- X area = 0;
- X case 2:
- X node += area*1024;
- X sdn.sdn_add.a_len = 2;
- X sdn.sdn_family = AF_DECnet;
- X sdn.sdn_add.a_addr[0] = node % 256;
- X sdn.sdn_add.a_addr[1] = node / 256;
- X break;
- X default:
- X if ((np = getnodebyname(machine)) == NULL) {
- X fprintf(stderr,
- X "%s: Unknown host.\n", machine);
- X return (-1);
- X } else {
- X bcopy(np->n_addr,
- X (char *) sdn.sdn_add.a_addr,
- X np->n_length);
- X sdn.sdn_add.a_len = np->n_length;
- X sdn.sdn_family = np->n_addrtype;
- X }
- X break;
- X }
- X sdn.sdn_objnum = 0;
- X sdn.sdn_flags = 0;
- X sdn.sdn_objnamel = strlen("NNTP");
- X bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
- X
- X if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
- X nerror("socket");
- X return (-1);
- X }
- X
- X /* And then connect */
- X
- X if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
- X nerror("connect");
- X close(s);
- X return (-1);
- X }
- X
- X return (s);
- X}
- X#endif
- X
- X
- X
- X/*
- X * handle_server_response
- X *
- X * Print some informative messages based on the server's initial
- X * response code. This is here so inews, rn, etc. can share
- X * the code.
- X *
- X * Parameters: "response" is the response code which the
- X * server sent us, presumably from "server_init",
- X * above.
- X * "server" is the news server we got the
- X * response code from.
- X *
- X * Returns: -1 if the error is fatal (and we should exit).
- X * 0 otherwise.
- X *
- X * Side effects: None.
- X */
- X
- handle_server_response(response, server)
- int response;
- char *server;
- X{
- X switch (response) {
- X case OK_NOPOST: /* fall through */
- X printf(
- X "NOTE: This machine does not have permission to post articles.\n");
- X printf(
- X " Please don't waste your time trying.\n\n");
- X
- X case OK_CANPOST:
- X return (0);
- X break;
- X
- X case ERR_ACCESS:
- X printf(
- X "This machine does not have permission to use the %s news server.\n",
- X server);
- X return (-1);
- X break;
- X
- X default:
- X printf("Unexpected response code from %s news server: %d\n",
- X server, response);
- X return (-1);
- X break;
- X }
- X /*NOTREACHED*/
- X}
- X
- X
- X/*
- X * put_server -- send a line of text to the server, terminating it
- X * with CR and LF, as per ARPA standard.
- X *
- X * Parameters: "string" is the string to be sent to the
- X * server.
- X *
- X * Returns: Nothing.
- X *
- X * Side effects: Talks to the server.
- X *
- X * Note: This routine flushes the buffer each time
- X * it is called. For large transmissions
- X * (i.e., posting news) don't use it. Instead,
- X * do the fprintf's yourself, and then a final
- X * fflush.
- X */
- X
- void
- put_server(string)
- char *string;
- X{
- X#ifdef DEBUG
- X fprintf(stderr, ">>> %s\n", string);
- X#endif
- X fprintf(ser_wr_fp, "%s\r\n", string);
- X (void) fflush(ser_wr_fp);
- X}
- X
- X
- X/*
- X * get_server -- get a line of text from the server. Strips
- X * CR's and LF's.
- X *
- X * Parameters: "string" has the buffer space for the
- X * line received.
- X * "size" is the size of the buffer.
- X *
- X * Returns: -1 on error, 0 otherwise.
- X *
- X * Side effects: Talks to server, changes contents of "string".
- X */
- X
- get_server(string, size)
- char *string;
- int size;
- X{
- X register char *cp;
- X char *index();
- X
- X if (fgets(string, size, ser_rd_fp) == NULL)
- X return (-1);
- X
- X if ((cp = index(string, '\r')) != NULL)
- X *cp = '\0';
- X else if ((cp = index(string, '\n')) != NULL)
- X *cp = '\0';
- X#ifdef DEBUG
- X fprintf(stderr, "<<< %s\n", string);
- X#endif
- X
- X return (0);
- X}
- X
- X
- X/*
- X * close_server -- close the connection to the server, after sending
- X * the "quit" command.
- X *
- X * Parameters: None.
- X *
- X * Returns: Nothing.
- X *
- X * Side effects: Closes the connection with the server.
- X * You can't use "put_server" or "get_server"
- X * after this routine is called.
- X */
- X
- void
- close_server()
- X{
- X char ser_line[256];
- X
- X if (ser_wr_fp == NULL || ser_rd_fp == NULL)
- X return;
- X
- X put_server("QUIT");
- X (void) get_server(ser_line, sizeof(ser_line));
- X
- X (void) fclose(ser_wr_fp);
- X (void) fclose(ser_rd_fp);
- X}
- X
- X#ifdef USG
- bzero(p, l)
- X register char *p;
- X register int l;
- X{
- X while (l-- > 0)
- X *p++ = 0;
- X}
- X#endif USG
- END_OF_FILE
- if test 10189 -ne `wc -c <'./common/clientlib.c'`; then
- echo shar: \"'./common/clientlib.c'\" unpacked with wrong size!
- fi
- # end of './common/clientlib.c'
- fi
- if test -f './server/newnews.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./server/newnews.c'\"
- else
- echo shar: Extracting \"'./server/newnews.c'\" \(10834 characters\)
- sed "s/^X//" >'./server/newnews.c' <<'END_OF_FILE'
- X#ifndef lint
- static char *sccsid = "@(#)newnews.c 1.19 (Berkeley) 2/6/88";
- X#endif
- X
- X#include "common.h"
- X#include "time.h"
- X
- X#ifdef LOG
- int nn_told = 0;
- int nn_took = 0;
- X#endif
- X
- X
- X/*
- X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
- X *
- X * Return the message-id's of any news articles past
- X * a certain date and time, within the specified distributions.
- X *
- X */
- X
- newnews(argc, argv)
- X register int argc;
- X char *argv[];
- X{
- X register char *cp, *ngp;
- X char *key;
- X char datebuf[32];
- X char line[MAXBUFLEN];
- X char **distlist, **histlist;
- X static char **nglist;
- X int distcount, ngcount, histcount;
- X int all;
- X FILE *fp;
- X long date;
- X long dtol();
- X char *ltod();
- X#ifdef USG
- X FILE *tmplst;
- X int i;
- X char *tmpfile;
- X#endif USG
- X
- X if (argc < 4) {
- X printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
- X ERR_CMDSYN);
- X (void) fflush(stdout);
- X return;
- X }
- X
- X#ifdef LOG
- X sprintf(line, "%s newnews %s %s %s %s %s",
- X hostname,
- X argv[1],
- X argv[2],
- X argv[3],
- X (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
- X (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
- X syslog(LOG_INFO, line);
- X#endif
- X
- X all = (argv[1][0] == '*' && argv[1][1] == '\0');
- X if (!all) {
- X ngcount = get_nglist(&nglist, argv[1]);
- X if (ngcount == 0) {
- X printf("%d Bogus newsgroup specifier: %s\r\n",
- X ERR_CMDSYN, argv[1]);
- X (void) fflush(stdout);
- X return;
- X }
- X }
- X
- X /* YYMMDD HHMMSS */
- X if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
- X printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
- X ERR_CMDSYN);
- X (void) fflush(stdout);
- X return;
- X }
- X
- X (void) strcpy(datebuf, argv[2]);
- X (void) strcat(datebuf, argv[3]);
- X
- X argc -= 4;
- X argv += 4;
- X
- X /*
- X * Flame on. The history file is not stored in GMT, but
- X * in local time. So we have to convert GMT to local time
- X * if we're given GMT, otherwise we need only chop off the
- X * the seconds. Such braindamage.
- X */
- X
- X key = datebuf; /* Unless they specify GMT */
- X
- X if (argc > 0) {
- X if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
- X date = dtol(datebuf);
- X if (date < 0) {
- X printf("%d Invalid date specification.\r\n",
- X ERR_CMDSYN);
- X (void) fflush(stdout);
- X return;
- X }
- X date = gmt_to_local(date);
- X key = ltod(date);
- X ++argv;
- X --argc;
- X }
- X }
- X
- X /* So, key now points to the local time, but we need to zap secs */
- X
- X key[10] = '\0';
- X
- X distcount = 0;
- X if (argc > 0) {
- X distcount = get_distlist(&distlist, *argv);
- X if (distcount < 0) {
- X printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
- X *argv);
- X (void) fflush(stdout);
- X return;
- X }
- X }
- X
- X#ifdef USG
- X if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
- X (tmplst = fopen(tmpfile, "w+")) == NULL) {
- X printf("%d Cannot process history file.\r\n", ERR_FAULT);
- X (void) fflush(stdout);
- X return;
- X }
- X
- X for (i = 0; i < 9; i++) {
- X sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
- X#endif USG
- X
- X fp = fopen(historyfile, "r");
- X if (fp == NULL) {
- X#ifdef SYSLOG
- X syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
- X#endif
- X#ifndef USG
- X printf("%d Cannot open history file.\r\n", ERR_FAULT);
- X (void) fflush(stdout);
- X return;
- X#else USG
- X continue;
- X#endif USG
- X }
- X
- X#ifndef USG
- X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
- X#endif not USG
- X
- X if (seekuntil(fp, key, line, sizeof (line)) < 0) {
- X#ifndef USG
- X printf(".\r\n");
- X (void) fflush(stdout);
- X#endif not USG
- X (void) fclose(fp);
- X#ifndef USG
- X return;
- X#else USG
- X continue;
- X#endif USG
- X }
- X
- X/*
- X * History file looks like:
- X *
- X * <1569@emory.UUCP> 01/22/86 09:19 net.micro.att/899 ucb.general/2545
- X * ^--tab ^--tab ^--space ^sp\0
- X * Sometimes the newsgroups are missing; we try to be robust and
- X * ignore such bogosity. We tackle this by our usual parse routine,
- X * and break the list of articles in the history file into an argv
- X * array with one newsgroup per entry.
- X */
- X
- X do {
- X if ((cp = index(line, '\t')) == NULL)
- X continue;
- X
- X if ((ngp = index(cp+1, '\t')) == NULL) /* 2nd tab */
- X continue;
- X ++ngp; /* Points at newsgroup list */
- X if (*ngp == '\n')
- X continue;
- X histcount = get_histlist(&histlist, ngp);
- X if (histcount == 0)
- X continue;
- X
- X /*
- X * For each newsgroup on this line in the history
- X * file, check it against the newsgroup names we're given.
- X * If it matches, then see if we're hacking distributions.
- X * If so, open the file and match the distribution line.
- X */
- X
- X if (!all)
- X if (!ngmatch(restreql, 0, nglist, ngcount,
- X histlist, histcount))
- X continue;
- X
- X if (distcount)
- X if (!distmatch(distlist, distcount, histlist, histcount))
- X continue;
- X
- X *cp = '\0';
- X#ifdef USG
- X fputs(line, tmplst);
- X fputc('\n', tmplst);
- X#else not USG
- X putline(line);
- X#endif not USG
- X#ifdef LOG
- X nn_told++;
- X#endif
- X } while (fgets(line, sizeof(line), fp) != NULL);
- X
- X#ifndef USG
- X putchar('.');
- X putchar('\r');
- X putchar('\n');
- X (void) fflush(stdout);
- X#endif
- X (void) fclose(fp);
- X#ifdef USG
- X }
- X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
- X rewind(tmplst);
- X while (fgets(line, sizeof(line), tmplst) != NULL)
- X putline(line);
- X putchar('.');
- X putchar('\r');
- X putchar('\n');
- X (void) fflush(stdout);
- X (void) fclose(tmplst);
- X (void) unlink(tmpfile);
- X#endif USG
- X}
- X
- X
- X/*
- X * seekuntil -- seek through the history file looking for
- X * a line with date "key". Get that line, and return.
- X *
- X * Parameters: "fp" is the active file.
- X * "key" is the date, in form YYMMDDHHMM (no SS)
- X * "line" is storage for the first line we find.
- X *
- X * Returns: -1 on error, 0 otherwise.
- X *
- X * Side effects: Seeks in history file, modifies line.
- X */
- X
- seekuntil(fp, key, line, linesize)
- X FILE *fp;
- X char *key;
- X char *line;
- X int linesize;
- X{
- X char datetime[32];
- X register int c;
- X register long top, bot, mid;
- X
- X bot = 0;
- X (void) fseek(fp, 0L, 2);
- X top = ftell(fp);
- X for(;;) {
- X mid = (top+bot)/2;
- X (void) fseek(fp, mid, 0);
- X do {
- X c = getc(fp);
- X mid++;
- X } while (c != EOF && c!='\n');
- X if (!getword(fp, datetime, line, linesize)) {
- X return (-1);
- X }
- X switch (compare(key, datetime)) {
- X case -2:
- X case -1:
- X case 0:
- X if (top <= mid)
- X break;
- X top = mid;
- X continue;
- X case 1:
- X case 2:
- X bot = mid;
- X continue;
- X }
- X break;
- X }
- X (void) fseek(fp, bot, 0);
- X while(ftell(fp) < top) {
- X if (!getword(fp, datetime, line, linesize)) {
- X return (-1);
- X }
- X switch(compare(key, datetime)) {
- X case -2:
- X case -1:
- X case 0:
- X break;
- X case 1:
- X case 2:
- X continue;
- X }
- X break;
- X }
- X
- X return (0);
- X}
- X
- X
- compare(s, t)
- X register char *s, *t;
- X{
- X for (; *s == *t; s++, t++)
- X if (*s == 0)
- X return(0);
- X return (*s == 0 ? -1:
- X *t == 0 ? 1:
- X *s < *t ? -2:
- X 2);
- X}
- X
- X
- getword(fp, w, line, linesize)
- X FILE *fp;
- X register char *w;
- X char *line;
- X int linesize;
- X{
- X register char *cp;
- X
- X if (fgets(line, linesize, fp) == NULL)
- X return (0);
- X if (cp = index(line, '\t')) {
- X/*
- X * The following gross hack is present because the history file date
- X * format is braindamaged. They like "mm/dd/yy hh:mm", which is useless
- X * for relative comparisons of dates using something like atoi() or
- X * strcmp. So, this changes their format into yymmddhhmm. Sigh.
- X *
- X * 12345678901234 ("x" for cp[x])
- X * mm/dd/yy hh:mm (their lousy representation)
- X * yymmddhhmm (our good one)
- X * 0123456789 ("x" for w[x])
- X */
- X *cp = '\0';
- X (void) strncpy(w, cp+1, 15);
- X w[0] = cp[7]; /* Years */
- X w[1] = cp[8];
- X w[2] = cp[1]; /* Months */
- X w[3] = cp[2];
- X w[4] = cp[4]; /* Days */
- X w[5] = cp[5];
- X w[6] = cp[10]; /* Hours */
- X w[7] = cp[11];
- X w[8] = cp[13]; /* Minutes */
- X w[9] = cp[14];
- X w[10] = '\0';
- X } else
- X w[0] = '\0';
- X return (1);
- X}
- X
- X
- X/*
- X * distmatch -- see if a file matches a set of distributions.
- X * We have to do this by (yech!) opening the file, finding
- X * the Distribution: line, if it has one, and seeing if the
- X * things match.
- X *
- X * Parameters: "distlist" is the distribution list
- X * we want.
- X * "distcount" is the count of distributions in it.
- X * "grouplist" is the list of groups (articles)
- X * for this line of the history file. Note that
- X * this isn't quite a filename.
- X * "groupcount" is the count of groups in it.
- X *
- X * Returns: 1 if the article is in the given distribution.
- X * 0 otherwise.
- X */
- X
- distmatch(distlist, distcount, grouplist, groupcount)
- X char *distlist[];
- X int distcount;
- X char *grouplist[];
- X int groupcount;
- X{
- X register char c;
- X register char *cp;
- X register FILE *fp;
- X register int i, j;
- X char buf[MAXBUFLEN];
- X
- X (void) strcpy(buf, spooldir);
- X (void) strcat(buf, "/");
- X (void) strcat(buf, grouplist[0]);
- X
- X for (cp = buf; *cp; cp++)
- X if (*cp == '.')
- X *cp = '/';
- X
- X fp = fopen(buf, "r");
- X if (fp == NULL) {
- X#ifdef SYSLOG
- X syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
- X#endif
- X return (0);
- X }
- X
- X while (fgets(buf, sizeof (buf), fp) != NULL) {
- X if ((c = buf[0]) == '\n') /* End of header */
- X break;
- X if (c != 'd' && c != 'D')
- X continue;
- X cp = index(cp + 1, '\n');
- X if (cp)
- X *cp = '\0';
- X cp = index(buf, ':');
- X if (cp == NULL)
- X continue;
- X *cp = '\0';
- X if (!strcasecmp(buf, "distribution")) {
- X for (i = 0; i < distcount; ++i) {
- X if (!strcasecmp(cp + 2, distlist[i])) {
- X (void) fclose(fp);
- X return (1);
- X }
- X }
- X (void) fclose(fp);
- X return (0);
- X }
- X }
- X
- X (void) fclose(fp);
- X
- X /*
- X * We've finished the header with no distribution field.
- X * So we'll assume that the distribution is the characters
- X * up to the first dot in the newsgroup name.
- X */
- X
- X for (i = 0; i < groupcount; i++) {
- X cp = index(grouplist[i], '.');
- X if (cp)
- X *cp = '\0';
- X for (j = 0; j < distcount; j++)
- X if (!strcasecmp(grouplist[i], distlist[j]))
- X return (1);
- X }
- X
- X return (0);
- X}
- X
- X
- X/*
- X * get_histlist -- return a nicely set up array of newsgroups
- X * (actually, net.foo.bar/article_num) along with a count.
- X *
- X * Parameters: "array" is storage for our array,
- X * set to point at some static data.
- X * "list" is the history file newsgroup list.
- X *
- X * Returns: Number of group specs found.
- X *
- X * Side effects: Changes static data area.
- X */
- X
- get_histlist(array, list)
- X char ***array;
- X char *list;
- X{
- X register int histcount;
- X register char *cp;
- X static char **hist_list = (char **) NULL;
- X
- X cp = index(list, '\n');
- X if (cp)
- X *cp-- = '\0';
- X histcount = parsit(list, &hist_list);
- X *array = hist_list;
- X return (histcount);
- X}
- X
- X
- X/*
- X * get_nglist -- return a nicely set up array of newsgroups
- X * along with a count, when given an NNTP-spec newsgroup list
- X * in the form ng1,ng2,ng...
- X *
- X * Parameters: "array" is storage for our array,
- X * set to point at some static data.
- X * "list" is the NNTP newsgroup list.
- X *
- X * Returns: Number of group specs found.
- X *
- X * Side effects: Changes static data area.
- X */
- X
- get_nglist(array, list)
- X char ***array;
- X char *list;
- X{
- X register char *cp;
- X register int ngcount;
- X
- X for (cp = list; *cp != '\0'; ++cp)
- X if (*cp == ',')
- X *cp = ' ';
- X
- X ngcount = parsit(list, array);
- X
- X return (ngcount);
- X}
- END_OF_FILE
- if test 10834 -ne `wc -c <'./server/newnews.c'`; then
- echo shar: \"'./server/newnews.c'\" unpacked with wrong size!
- fi
- # end of './server/newnews.c'
- fi
- if test -f './xfer/nntpxfer.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./xfer/nntpxfer.c'\"
- else
- echo shar: Extracting \"'./xfer/nntpxfer.c'\" \(10068 characters\)
- sed "s/^X//" >'./xfer/nntpxfer.c' <<'END_OF_FILE'
- X/*
- X * nntpxfer
- X *
- X * Connects to the specified nntp server, and transfers all new news
- X * since the last successful invocation.
- X *
- X * last successful invocation date and time are stored in a file at
- X * /usr/spool/news/nntp.<hostname> as
- X * groups YYMMDD HHMMSS distributions\n
- X * in case you need to edit it. You can also override this on
- X * the command line in the same format, in which case the file won't
- X * be updated.
- X *
- X * Brian Kantor, UCSD 1986
- X * (some bug fixes by ambar@athena.mit.edu)
- X */
- X
- X#define DEBUG
- X
- X/* you'd think that 4096 articles at one go is enough.... */
- X#define MAXARTS 4096
- X
- X#include <sys/types.h>
- X#include <sys/dir.h>
- X#include <sys/socket.h>
- X#include <sys/stat.h>
- X#include <sys/ioctl.h>
- X#include <sys/file.h>
- X#include <sys/time.h>
- X#include <sys/wait.h>
- X#include <sys/resource.h>
- X
- X#include <net/if.h>
- X#include <netinet/in.h>
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <ctype.h>
- X#include <netdb.h>
- X#include <signal.h>
- X#include <dbm.h>
- X
- X#define INEWS "/usr/lib/news/inews -p"
- X#define HIST "/usr/lib/news/history"
- X
- char *malloc();
- char *strcpy();
- char *strcat();
- long time();
- u_long inet_addr();
- X
- extern int errno;
- char *artlist[MAXARTS];
- int server; /* stream socket to the nntp server */
- int newart, dupart, misart;
- X
- main(argc, argv)
- int argc;
- char *argv[];
- X {
- X FILE *dtfile; /* where last xfer date/time stored */
- X char buf[BUFSIZ];
- X char lastdate[16];
- X char distributions[BUFSIZ];
- X char dtname[128];
- X char newsgroups[BUFSIZ];
- X char lasttime[16];
- X int connected = 0; /* 1 = connected */
- X int i;
- X int omitupdate = 0; /* 1 = don't update datetime */
- X long clock;
- X long newdate, newtime;
- X struct hostent *hp;
- X struct servent *sp;
- X struct sockaddr_in sin;
- X struct tm *now;
- X
- X /* OPTIONS
- X argv[1] MUST be the host name
- X argv[2-4] MAY be "newsgroups YYMMDD HHMMSS"
- X argv[5] MAY be distributions
- X (otherwise use 2-4/5 from the file
- X "/usr/spool/news/nntp.hostname")
- X */
- X
- X if (argc != 2 && argc != 5 && argc != 6)
- X {
- X (void) printf("Usage: %s host [groups YYMMDD HHMMSS [<dist>]]\n",
- X argv[0]);
- X exit(1);
- X }
- X
- X if (argc > 2)
- X {
- X omitupdate++;
- X (void) strcpy(newsgroups, argv[2]);
- X (void) strcpy(lastdate, argv[3]);
- X (void) strcpy(lasttime, argv[4]);
- X (void) strcpy(distributions, "");
- X if (argc > 5)
- X (void) strcpy(distributions, argv[5]);
- X }
- X else
- X {
- X (void) strcpy(dtname, "/usr/spool/news/nntp.");
- X (void) strcat(dtname, argv[1]);
- X dtfile = fopen(dtname, "r");
- X if (dtfile == NULL)
- X {
- X (void) printf("%s not found; using * 860101 000000 \n",
- X dtname);
- X (void) strcpy(newsgroups, "*");
- X (void) strcpy(lastdate, "860101");
- X (void) strcpy(lasttime, "000000");
- X (void) strcpy(distributions, "");
- X }
- X else
- X {
- X if (fscanf(dtfile, "%s %s %s %s",
- X newsgroups, lastdate, lasttime, distributions) < 3)
- X {
- X (void) printf("%s invalid; using * 860101 000000\n",
- X dtname);
- X (void) strcpy(newsgroups, "*");
- X (void) strcpy(lastdate, "860101");
- X (void) strcpy(lasttime, "000000");
- X (void) strcpy(distributions, "");
- X }
- X (void) fclose(dtfile);
- X }
- X clock = time((long *)0);
- X now = gmtime(&clock);
- X newdate = (now->tm_year * 10000) +
- X ((now->tm_mon + 1) * 100) + now->tm_mday;
- X newtime = (now->tm_hour * 10000) +
- X (now->tm_min * 100) + now->tm_sec;
- X }
- X
- X#ifdef DEBUG
- X (void) printf("newsgroups = '%s'\n", newsgroups);
- X (void) printf("date = '%s'\n", lastdate);
- X (void) printf("time = '%s'\n", lasttime);
- X (void) printf("distributions = '%s'\n", distributions);
- X (void) printf("now is = %06d %06d\n", newdate, newtime);
- X#endif
- X
- X if (dbminit(HIST) < 0)
- X {
- X perror("couldn't open history file");
- X exit(1);
- X }
- X
- X sin.sin_addr.s_addr = inet_addr(argv[1]);
- X if (sin.sin_addr.s_addr != -1)
- X {
- X sin.sin_family = AF_INET;
- X }
- X else
- X {
- X hp = gethostbyname(argv[1]);
- X if (hp == NULL)
- X {
- X (void) printf("%s: unknown host\n", argv[1]);
- X exit(1);
- X }
- X
- X sin.sin_family = hp->h_addrtype;
- X#ifdef BSD43
- X bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
- X hp->h_length);
- X#else BSD43
- X bcopy(hp->h_addr, (caddr_t)&sin.sin_addr,
- X hp->h_length);
- X#endif BSD43
- X }
- X
- X sp = getservbyname("nntp", "tcp");
- X if (sp == NULL)
- X {
- X perror("nntp/tcp");
- X exit(1);
- X }
- X
- X sin.sin_port = sp->s_port;
- X
- X do {
- X server = socket(AF_INET, SOCK_STREAM, 0);
- X if (server < 0)
- X {
- X perror("nntpxfer: socket");
- X exit(1);
- X }
- X
- X if (connect(server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
- X {
- X#ifdef BSD43
- X if (hp && hp->h_addr_list[1])
- X {
- X hp->h_addr_list++;
- X bcopy(hp->h_addr_list[0],
- X (caddr_t)&sin.sin_addr, hp->h_length);
- X (void) close(server);
- X continue;
- X }
- X#endif BSD43
- X perror("nntpxfer: connect");
- X exit(1);
- X }
- X connected++;
- X }
- X while (connected == 0);
- X
- X#ifdef DEBUG
- X (void) printf("connected to nntp server at %s\n", argv[1]);
- X#endif
- X /*
- X * ok, at this point we're connected to the nntp daemon
- X * at the distant host.
- X */
- X
- X /* get the greeting herald */
- X (void) sockread(buf);
- X#ifdef DEBUG
- X (void) printf("%s\n", buf);
- X#endif
- X if (buf[0] != '2') /* uh-oh, something's wrong! */
- X {
- X (void) printf("protocol error: got '%s'\n", buf);
- X (void) close(server);
- X exit(1);
- X }
- X
- X
- X /* first, tell them we're a slave process to get priority */
- X sockwrite("SLAVE");
- X (void) sockread(buf);
- X#ifdef DEBUG
- X (void) printf("%s\n", buf);
- X#endif
- X if (buf[0] != '2') /* uh-oh, something's wrong! */
- X {
- X (void) printf("protocol error: got '%s'\n", buf);
- X (void) close(server);
- X exit(1);
- X }
- X
- X /* now, ask for a list of new articles */
- X if (strlen(distributions))
- X (void) sprintf(buf,"NEWNEWS %s %s %s GMT <%s>",
- X newsgroups, lastdate, lasttime, distributions);
- X else
- X (void) sprintf(buf,"NEWNEWS %s %s %s GMT",
- X newsgroups, lastdate, lasttime);
- X sockwrite(buf);
- X (void) sockread(buf);
- X#ifdef DEBUG
- X (void) printf("%s\n", buf);
- X#endif
- X if (buf[0] != '2') /* uh-oh, something's wrong! */
- X {
- X (void) printf("protocol error: got '%s'\n", buf);
- X (void) close(server);
- X exit(1);
- X }
- X /* and here comes the list, terminated with a "." */
- X#ifdef DEBUG
- X (void) printf("data\n");
- X#endif
- X while (1)
- X {
- X (void) sockread(buf);
- X if (!strcmp(buf,"."))
- X break;
- X if (wewant(buf))
- X {
- X if (newart > MAXARTS)
- X {
- X omitupdate++;
- X continue;
- X }
- X artlist[newart] = malloc((unsigned)(strlen(buf)+1));
- X (void) strcpy(artlist[newart], buf);
- X newart++;
- X }
- X else
- X dupart++;
- X }
- X#ifdef DEBUG
- X (void) printf(".\n%d new, %d dup articles\n", newart, dupart);
- X#endif
- X
- X /* now that we know which articles we want, retrieve them */
- X for (i=1; i < newart; i++)
- X (void) artfetch(artlist[i]);
- X
- X#ifdef DEBUG
- X (void) printf("%d missing articles\n", misart);
- X#endif
- X /* we're all done, so tell them goodbye */
- X sockwrite("QUIT");
- X (void) sockread(buf);
- X#ifdef DEBUG
- X (void) printf("%s\n", buf);
- X#endif
- X if (buf[0] != '2') /* uh-oh, something's wrong! */
- X {
- X (void) printf("error: got '%s'\n", buf);
- X (void) close(server);
- X exit(1);
- X }
- X (void) close(server);
- X
- X /* do we want to update the timestamp file? */
- X if (!omitupdate)
- X {
- X (void) sprintf(buf, "%s %06d %06d %s\n",
- X newsgroups, newdate, newtime, distributions);
- X#ifdef DEBUG
- X (void) printf("updating %s:\n\t%s\n", dtname, buf);
- X#endif
- X dtfile = fopen(dtname, "w");
- X if (dtfile == NULL)
- X {
- X perror(dtname);
- X exit(1);
- X }
- X (void) fputs(buf,dtfile);
- X (void) fclose(dtfile);
- X }
- X exit(0);
- X}
- X
- artfetch(articleid)
- char *articleid;
- X {
- X int lines = 0;
- X char buf[BUFSIZ];
- X FILE *inews;
- X
- X /* now, ask for the article */
- X (void) sprintf(buf,"ARTICLE %s", articleid);
- X sockwrite(buf);
- X (void) sockread(buf);
- X#ifdef DEBUG
- X (void) printf("%s\n", buf);
- X#endif
- X if (buf[0] == '4') /* missing article, just skipit */
- X {
- X misart++;
- X return(0);
- X }
- X
- X if (buf[0] != '2') /* uh-oh, something's wrong! */
- X {
- X (void) printf("protocol error: got '%s'\n", buf);
- X (void) close(server);
- X exit(1);
- X }
- X#ifdef DEBUG
- X (void) printf("command: %s\n", INEWS);
- X#endif
- X if ( (inews = popen(INEWS, "w")) == NULL)
- X {
- X perror(INEWS);
- X exit(1);
- X }
- X
- X /* and here comes the article, terminated with a "." */
- X#ifdef DEBUG
- X (void) printf("data\n");
- X#endif
- X while (1)
- X {
- X (void) sockread(buf);
- X if (buf[0] == '.' && buf[1] == '\0')
- X break;
- X lines++;
- X (void) strcat(buf,"\n");
- X (void) fputs(((buf[0] == '.') ? buf + 1 : buf),
- X inews);
- X }
- X#ifdef DEBUG
- X (void) printf(".\n%d lines\n", lines);
- X#endif
- X (void) fflush(inews);
- X (void) pclose(inews);
- X return(0);
- X }
- X
- int
- sockread(buf)
- char *buf;
- X {
- X char c;
- X int j = 0;
- X#ifdef BSD43
- X fd_set rf;
- X#else BSD43
- X int rf;
- X#endif BSD43
- X struct timeval tv;
- X int r;
- X char *p = buf;
- X
- X while ( 1 )
- X {
- X tv.tv_sec = 1800; /* 15 minutes */
- X tv.tv_usec = 0L;
- X#ifdef BSD43
- X FD_ZERO(&rf);
- X FD_SET(server, &rf);
- X#else BSD43
- X rf = 1 << server;
- X#endif BSD43
- X r = select(20, (fd_set *)&rf, (fd_set *)0, (fd_set *)&rf, &tv);
- X
- X if (r < 0)
- X {
- X if (errno == EINTR)
- X continue;
- X perror("getsock select");
- X exit(1);
- X }
- X if (r == 0)
- X {
- X printf("read timed out.\n");
- X exit(1);
- X }
- X
- X if (read(server, &c, 1) <= 0)
- X break;
- X
- X /* mask off any chance parity bits */
- X *p = c & 0x7f;
- X
- X /* look for end of line (== LF) */
- X if (c == 0x0a)
- X {
- X if (j > 0 && *(p-1) == 0x0d)
- X *(p-1) = '\0';
- X else
- X *p = '\0';
- X return(strlen(buf));
- X }
- X j++; p++;
- X }
- X perror("sockread");
- X (void) close(server);
- X exit(1);
- X /* NOTREACHED */
- X }
- X
- sockwrite(buf)
- char *buf;
- X {
- X register int sz;
- X char buf2[BUFSIZ];
- X#ifdef DEBUG
- X (void) printf(">>> %s\n", buf);
- X#endif
- X (void) strcpy(buf2,buf);
- X (void) strcat(buf2,"\r\n");
- X sz = strlen(buf2);
- X if (write(server,buf2,sz) != sz)
- X {
- X (void) printf("write error on server socket\n");
- X (void) close(server);
- X exit(1);
- X }
- X }
- X
- int
- wewant(articleid)
- char *articleid;
- X {
- X datum k, d;
- X char id[BUFSIZ];
- X char *p;
- X
- X /* remove any case sensitivity */
- X (void) strcpy(id, articleid);
- X p = id;
- X while (*p)
- X {
- X if (isupper(*p))
- X *p = tolower(*p);
- X p++;
- X }
- X
- X k.dptr = id;
- X k.dsize = strlen(articleid) + 1;
- X
- X d = fetch(k);
- X
- X if (d.dptr)
- X {
- X#ifdef DEBUG
- X (void) printf("dup: '%s'\n", articleid);
- X#endif
- X return(0);
- X }
- X
- X#ifdef DEBUG
- X (void) printf("new: '%s'\n", articleid);
- X#endif
- X return(1);
- X }
- END_OF_FILE
- if test 10068 -ne `wc -c <'./xfer/nntpxfer.c'`; then
- echo shar: \"'./xfer/nntpxfer.c'\" unpacked with wrong size!
- fi
- # end of './xfer/nntpxfer.c'
- fi
- if test -f './xmit/remote.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./xmit/remote.c'\"
- else
- echo shar: Extracting \"'./xmit/remote.c'\" \(9250 characters\)
- sed "s/^X//" >'./xmit/remote.c' <<'END_OF_FILE'
- X/*
- X** remote communication routines for NNTP/SMTP style communication.
- X**
- X** sendcmd - return TRUE on error.
- X**
- X** readreply - return reply code or FAIL for error;
- X** modifies buffer passed to it.
- X**
- X** converse - sendcmd() & readreply();
- X** return reply code or FAIL for error;
- X** modifies buffer passed to it.
- X**
- X** hello - establish connection with remote;
- X** check greeting code.
- X**
- X** goodbye - give QUIT command, and shut down connection.
- X**
- X** sfgets - safe fgets(); does fgets with TIMEOUT.
- X** (N.B.: possibly unportable stdio macro ref in here)
- X**
- X** rfgets - remote fgets() (calls sfgets());
- X** does SMTP dot escaping and
- X** \r\n -> \n conversion.
- X**
- X** sendfile - send a file with SMTP dot escaping and
- X** \n -> \r\n conversion.
- X**
- X** Erik E. Fair <fair@ucbarpa.berkeley.edu>
- X*/
- X
- X#include "nntpxmit.h"
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <errno.h>
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <setjmp.h>
- X#include <signal.h>
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#endif
- X#include "get_tcp_conn.h"
- X#include "nntp.h"
- X
- static jmp_buf SFGstack;
- FILE *rmt_rd;
- FILE *rmt_wr;
- char *sfgets();
- char *rfgets();
- X
- extern int errno;
- extern char Debug;
- extern char *errmsg();
- extern char *strcpy();
- extern void log();
- X
- X/*
- X** send cmd to remote, terminated with a CRLF.
- X*/
- sendcmd(cmd)
- char *cmd;
- X{
- X if (cmd == (char *)NULL)
- X return(TRUE); /* error */
- X dprintf(stderr, ">>> %s\n", cmd); /* DEBUG */
- X (void) fprintf(rmt_wr, "%s\r\n", cmd);
- X (void) fflush(rmt_wr);
- X return(ferror(rmt_wr));
- X}
- X
- X/*
- X** read a reply line from the remote server and return the code number
- X** as an integer, and the message in a buffer supplied by the caller.
- X** Returns FAIL if something went wrong.
- X*/
- readreply(buf, size)
- register char *buf;
- int size;
- X{
- X register char *cp;
- X register int len;
- X
- X if (buf == (char *)NULL || size <= 0)
- X return(FAIL);
- X
- X /*
- X ** make sure it's invalid, unless we say otherwise
- X */
- X buf[0] = '\0';
- X
- X /*
- X ** read one line from the remote
- X */
- X if (sfgets(buf, size, rmt_rd) == NULL)
- X return(FAIL); /* error reading from remote */
- X
- X /*
- X ** Make sure that what the remote sent us had a CRLF at the end
- X ** of the line, and then null it out.
- X */
- X if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
- X *(cp + 1) == '\n')
- X {
- X *cp = '\0';
- X } else
- X return(FAIL); /* error reading from remote */
- X
- X dprintf(stderr, "%s\n", buf); /* DEBUG */
- X /*
- X ** Skip any non-digits leading the response code
- X ** and then convert the code from ascii to integer for
- X ** return from this routine.
- X */
- X cp = buf;
- X while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
- X cp++; /* skip anything leading */
- X
- X if (*cp == '\0' || !isascii(*cp))
- X return(FAIL); /* error reading from remote */
- X
- X return(atoi(cp));
- X}
- X
- X/*
- X** send a command to the remote, and wait for a response
- X** returns the response code, and the message in the buffer
- X*/
- converse(buf, size)
- char *buf;
- int size;
- X{
- X register int resp;
- X
- X if (sendcmd(buf))
- X return(FAIL); /* Ooops! Something went wrong in xmit */
- X /*
- X ** Skip the silly 100 series messages, since they're not the
- X ** final response we can expect
- X */
- X while((resp = readreply(buf, size)) >= 100 && resp < 200)
- X continue;
- X return(resp);
- X}
- X
- X/*
- X** Contact the remote server and set up the two global FILE pointers
- X** to that descriptor.
- X**
- X** I can see the day when this routine will have 8 args: one for
- X** hostname, and one for each of the seven ISO Reference Model layers
- X** for networking. A curse upon those involved with the ISO protocol
- X** effort: may they be forced to use the network that they will create,
- X** as opposed to something that works (like the Internet).
- X*/
- hello(host, transport)
- char *host;
- int transport;
- X{ char *service;
- X char *rmode = "r";
- X char *wmode = "w";
- X char *e_fdopen = "fdopen(%d, \"%s\"): %s";
- X int socket0, socket1; /* to me (bad pun) */
- X char buf[BUFSIZ];
- X
- X switch(transport) {
- X case T_IP_TCP:
- X service = "nntp";
- X socket0 = get_tcp_conn(host, service);
- X break;
- X case T_DECNET:
- X#ifdef DECNET
- X (void) signal(SIGPIPE, SIG_IGN);
- X service = "NNTP";
- X socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
- X if (socket0 < 0) {
- X switch(errno) {
- X case EADDRNOTAVAIL:
- X socket0 = NOHOST;
- X break;
- X case ESRCH:
- X socket0 = NOSERVICE;
- X break;
- X }
- X }
- X break;
- X#else
- X log(L_WARNING, "no DECNET support compiled in");
- X return(FAIL);
- X#endif
- X case T_FD:
- X service = "with a smile";
- X socket0 = atoi(host);
- X break;
- X }
- X
- X if (socket0 < 0) {
- X switch(socket0) {
- X case NOHOST:
- X sprintf(buf, "%s host unknown", host);
- X log(L_WARNING, buf);
- X return(FAIL);
- X case NOSERVICE:
- X sprintf(buf, "%s service unknown: %s", host, service);
- X log(L_WARNING, buf);
- X return(FAIL);
- X case FAIL:
- X sprintf(buf, "%s hello: %s", host, errmsg(errno));
- X log(L_NOTICE, buf);
- X return(FAIL);
- X }
- X }
- X
- X if ((socket1 = dup(socket0)) < 0) {
- X sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
- X log(L_WARNING, buf);
- X (void) close(socket0);
- X return(FAIL);
- X }
- X
- X if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
- X sprintf(buf, e_fdopen, socket0, rmode);
- X log(L_WARNING, buf);
- X (void) close(socket0);
- X (void) close(socket1);
- X return(FAIL);
- X }
- X
- X if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
- X sprintf(buf, e_fdopen, socket1, wmode);
- X log(L_WARNING, buf);
- X (void) fclose(rmt_rd);
- X rmt_rd = (FILE *)NULL;
- X (void) close(socket1);
- X return(FAIL);
- X }
- X
- X switch(readreply(buf, sizeof(buf))) {
- X case OK_CANPOST:
- X case OK_NOPOST:
- X if (ferror(rmt_rd)) {
- X goodbye(DONT_WAIT);
- X return(FAIL);
- X }
- X break;
- X default:
- X if (buf[0] != '\0') {
- X char err[BUFSIZ];
- X
- X sprintf(err, "%s greeted us with %s", host, buf);
- X log(L_NOTICE, err);
- X }
- X goodbye(DONT_WAIT);
- X return(FAIL);
- X }
- X return(NULL);
- X}
- X
- X/*
- X** Say goodbye to the nice remote server.
- X**
- X** We trap SIGPIPE because the socket might already be gone.
- X*/
- goodbye(wait_for_reply)
- int wait_for_reply;
- X{
- X register ifunp pstate = signal(SIGPIPE, SIG_IGN);
- X
- X if (sendcmd("QUIT"))
- X wait_for_reply = FALSE; /* override, something's wrong. */
- X /*
- X ** I don't care what they say to me; this is just being polite.
- X */
- X if (wait_for_reply) {
- X char buf[BUFSIZ];
- X
- X (void) readreply(buf, sizeof(buf));
- X }
- X (void) fclose(rmt_rd);
- X rmt_rd = (FILE *)NULL;
- X (void) fclose(rmt_wr);
- X rmt_wr = (FILE *)NULL;
- X if (pstate != (ifunp)(-1));
- X (void) signal(SIGPIPE, pstate);
- X}
- X
- static
- to_sfgets()
- X{
- X longjmp(SFGstack, 1);
- X}
- X
- X/*
- X** `Safe' fgets, ala sendmail. This fgets will timeout after some
- X** period of time, on the assumption that if the remote did not
- X** return, they're gone.
- X** WARNING: contains a possibly unportable reference to stdio
- X** error macros.
- X*/
- char *
- sfgets(buf, size, fp)
- char *buf;
- int size;
- FILE *fp;
- X{
- X register char *ret;
- X int esave;
- X
- X if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
- X return((char *)NULL);
- X if (setjmp(SFGstack)) {
- X (void) alarm(0); /* reset alarm clock */
- X (void) signal(SIGALRM, SIG_DFL);
- X#ifdef apollo
- X fp->_flag |= _SIERR;
- X#else
- X fp->_flag |= _IOERR; /* set stdio error */
- X#endif
- X#ifndef ETIMEDOUT
- X errno = EPIPE; /* USG doesn't have ETIMEDOUT */
- X#else
- X errno = ETIMEDOUT; /* connection timed out */
- X#endif
- X return((char *)NULL); /* bad read, remote time out */
- X }
- X (void) signal(SIGALRM, to_sfgets);
- X (void) alarm(TIMEOUT);
- X ret = fgets(buf, size, fp);
- X esave = errno;
- X (void) alarm(0); /* reset alarm clock */
- X (void) signal(SIGALRM, SIG_DFL); /* reset SIGALRM */
- X errno = esave;
- X return(ret);
- X}
- X
- X/*
- X** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from
- X** the remote. Otherwise it returns its first argument, like fgets(3).
- X*/
- char *
- rfgets(buf, size, fp)
- char *buf;
- int size;
- FILE *fp;
- X{
- X register char *cp = buf;
- X register int len;
- X
- X if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
- X return((char *)NULL);
- X *cp = '\0';
- X if (sfgets(buf, size, fp) == (char *)NULL)
- X return((char *)NULL);
- X
- X /* <CRLF> => '\n' */
- X if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') {
- X *cp++ = '\n';
- X *cp = '\0';
- X }
- X
- X /* ".\n" => EOF */
- X cp = buf;
- X if (*cp++ == '.' && *cp == '\n') {
- X return((char *)NULL); /* EOF */
- X }
- X
- X /* Dot escaping */
- X if (buf[0] == '.')
- X (void) strcpy(&buf[0], &buf[1]);
- X return(buf);
- X}
- X
- X/*
- X** send the contents of an open file descriptor to the remote,
- X** with appropriate RFC822 filtering (e.g. CRLF line termination,
- X** and dot escaping). Return FALSE if something went wrong.
- X*/
- sendfile(fp)
- FILE *fp;
- X{
- X register int c;
- X register FILE *remote = rmt_wr;
- X register int nl = TRUE; /* assume we start on a new line */
- X
- X/*
- X** I'm using putc() instead of fputc();
- X** why do a subroutine call when you don't have to?
- X** Besides, this ought to give the C preprocessor a work-out.
- X*/
- X#define PUTC(c) if (putc(c, remote) == EOF) return(FALSE)
- X
- X if (fp == (FILE *)NULL)
- X return(FALSE);
- X
- X /*
- X ** the second test makes no sense to me,
- X ** but System V apparently needed it...
- X */
- X while((c = fgetc(fp)) != EOF && !feof(fp)) {
- X switch(c) {
- X case '\n':
- X PUTC('\r'); /* \n -> \r\n */
- X PUTC(c);
- X nl = TRUE; /* for dot escaping */
- X break;
- X case '.':
- X if (nl) {
- X PUTC(c); /* add a dot */
- X nl = FALSE;
- X }
- X PUTC(c);
- X break;
- X default:
- X PUTC(c);
- X nl = FALSE;
- X break;
- X }
- X }
- X if (!nl) {
- X PUTC('\r');
- X PUTC('\n');
- X }
- X return( !(sendcmd(".") || ferror(fp)) );
- X}
- END_OF_FILE
- if test 9250 -ne `wc -c <'./xmit/remote.c'`; then
- echo shar: \"'./xmit/remote.c'\" unpacked with wrong size!
- fi
- # end of './xmit/remote.c'
- fi
- echo shar: End of archive 6 \(of 9\).
- cp /dev/null ark6isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 9 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-